package com.hitqz.robot.biz.flow.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.cache.Cache;
import com.hitqz.robot.biz.flow.config.FlowInterruptException;
import com.hitqz.robot.biz.flow.domain.common.FailedCodeEnum;
import com.hitqz.robot.biz.flow.domain.dto.NodeDto;
import com.hitqz.robot.biz.flow.service.LiteFlowService;
import com.hitqz.robot.biz.flow.domain.common.ResponseResult;
import com.hitqz.robot.biz.flow.domain.constant.FlowConstant;
import com.hitqz.robot.biz.flow.domain.dto.ChainDto;
import com.hitqz.robot.biz.flow.domain.dto.SaveRuleDto;
import com.hitqz.robot.biz.flow.domain.vo.NodeGroupItemVo;
import com.hitqz.robot.biz.flow.domain.vo.NodeGroupVo;
import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.flow.FlowBus;
import com.yomahub.liteflow.flow.LiteflowResponse;
import com.yomahub.liteflow.flow.element.Chain;
import com.yomahub.liteflow.flow.element.Node;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.*;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @author wengyx
 * @date 2023/09/08
 */
@Service
@Slf4j
public class LiteFlowServiceImpl implements LiteFlowService {

    @Resource(name = "flowCache")
    private Cache<String,Object> flowCache;

    @Resource
    private FlowExecutor flowExecutor;

    @Override
    public List<NodeGroupVo> getNodePanelList() {
        Map<String, Node> nodeMap = FlowBus.getNodeMap();
        AtomicInteger index = new AtomicInteger(2);
        Map<String, List<NodeGroupItemVo>> collect = nodeMap.keySet().stream().sorted()
                .map(k -> NodeGroupItemVo.convertNode2Vo(index.getAndIncrement(), nodeMap.get(k)))
                .collect(Collectors.groupingBy(NodeGroupItemVo::getProtocol));
        List<NodeGroupVo> list = new ArrayList<>(4);
        collect.keySet().forEach(k -> {
            list.add(NodeGroupVo.builder().id(k).header(k).children(collect.get(k)).build());
        });
        log.info("node：{}", list);
        return list;
    }

    @Override
    public ResponseResult<?> executeChain(String chainId, Integer cmd) {
        if (!FlowBus.containChain(chainId)) {
            return ResponseResult.fail(FailedCodeEnum.CHAIN_NO_DEPLOY);
        }
        if (Objects.equals(cmd, 0)) {
            flowCache.put("stop",true);
        }
        if (Objects.equals(cmd, 1)) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            Future<LiteflowResponse> liteflowResponseFuture = flowExecutor.execute2Future(chainId, null);
        }
        return ResponseResult.success();
    }

    @Override
    public void removeChain(String chainId) {
        //删除缓存
        if (FlowBus.containChain(chainId)) {
            FlowBus.removeChain(chainId);
        }
        //删除文件
        File jsonFile = new File(FlowConstant.FILE_SAVE_PATH + chainId + ".json");
        if (jsonFile.exists()){
            jsonFile.delete();
        }
        File txtFile = new File(FlowConstant.FILE_SAVE_PATH + chainId + ".txt");
        if (txtFile.exists()){
            txtFile.delete();
        }
    }

    @Override
    public SaveRuleDto getChain(String chainId) {
        String el = "";
        String json = "";
        File jsonFile = new File(FlowConstant.FILE_SAVE_PATH + chainId + ".json");
        if (jsonFile.exists()){
            json = FileUtil.readUtf8String(jsonFile);
        }
        File txtFile = new File(FlowConstant.FILE_SAVE_PATH + chainId + ".txt");
        if (txtFile.exists()){
            el = FileUtil.readUtf8String(txtFile);
        }
        SaveRuleDto dto = new SaveRuleDto();
        dto.setChainId(chainId);
        dto.setName(chainId);
        dto.setEl(el);
        dto.setJson(json);
        return dto;
    }

    @Override
    public List<ChainDto> getChainsList() {
        Map<String, Chain> chainMap = FlowBus.getChainMap();
        if (chainMap.isEmpty()) {
            return new ArrayList<>();
        }
        List<ChainDto> list = chainMap.keySet().stream()
                .map(k -> ChainDto.builder()
                        .name(k)
                        .id(k)
                        .nodes(NodeDto.getChainNodes(chainMap.get(k)))
                        .build())
                .collect(Collectors.toList());
        log.info("chain：{}",list);
        return list;
    }

    @Override
    public ResponseResult<?> setChain(String chainId, String el) {
        if (StrUtil.isBlank(chainId)) {
            return ResponseResult.fail(FailedCodeEnum.BAD_REQUEST);
        }
        if (StrUtil.isBlank(el)) {
            return ResponseResult.fail(FailedCodeEnum.INVALID_EL_DATA);
        }
        if (!LiteFlowChainELBuilder.validate(el)) {
            return ResponseResult.fail(FailedCodeEnum.INVALID_EL_RULE);
        }
        LiteFlowChainELBuilder.createChain().setChainId(chainId).setEL(el).build();
        return ResponseResult.success();
    }


}
